﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;
using RushTracker.Core.Models.Torrents;
using RushTracker.Core.BEncoding;
using RushTracker.Core.Models;
using System.IO;
using System.Security.Cryptography;

namespace RushTracker.Web.UI.Controllers
{
    public class TorrentsController : RushTrackerController
    {
        public ActionResult Index()
        {
            ViewData["torrentList"] = DataRepository.GetLatestTorrents(20, null);
            ViewData["categories"] = new List<Category>();
            return View();
        }

        [ActionName("category")]
        public string ListByCategory(int categoryId)
        {
            return "ListByCategory: " + categoryId;
        }

        public string ListByTags(string tags)
        {
            return "ListByTags: " + tags.Replace("+", "<br/>");
        }

        public ActionResult Show(int torrentId)
        {
            Torrent t = DataRepository.GetObjectById<Torrent>(torrentId);

            if (t == null)
            {
                // errror
            }

            if (Request.IsAjaxRequest())
            {
                return PartialView("~/Views/Torrents/Controls/FileList.ascx", t.Information.Files);
            }

            ViewData.Model = t;
            return View();
        }

        [Authorize]
        public ActionResult Edit(int torrentId)
        {
            return View();
        }

        public string Download(int torrentId)
        {
            Torrent t = DataRepository.GetObjectById<Torrent>(torrentId);

            if (t == null)
            {
                // errror
            }

            string fileContents = "";

            using (StreamReader reader = new StreamReader(Path.Combine(Server.MapPath(Site.UploadPath), t.Information.FileName)))
            {
                fileContents = reader.ReadToEnd();
                reader.Close();
            }

            return fileContents;
        }

        // GET /upload
        [Authorize]
        public ActionResult Upload()
        {
            Category c1 = new Category() { Name = "Foo", Id = 1 };
            Category c2 = new Category() { Name = "Bar", Id = 2 };

            List<SelectListItem> categories = new List<SelectListItem>();
            categories.Add(new SelectListItem() { Text = c1.Name, Value = c1.Id.ToString() });
            categories.Add(new SelectListItem() { Text = c2.Name, Value = c2.Id.ToString() });

            ViewData["torrentcategories"] = categories;

            return View();
        }

        // POST /upload
        [Authorize]
        [HttpPost]
        public ActionResult Upload(FormCollection form)
        {
            if (HttpContext.Request.Files.Count > 0 && HttpContext.Request.Files[0].ContentLength > 0)
            {
                Torrent torrent = new Torrent();
                BEncodedDictionary torrentDictionary = null;
                BEncodedDictionary info = null;

                try
                {
                    torrentDictionary = BEncodedDictionary.DecodeTorrent(HttpContext.Request.Files[0].InputStream);
                    info = (BEncodedDictionary)torrentDictionary["info"];
                }
                catch (BEncodingException)
                {
                    return RedirectToAction("Upload");
                }

                torrent.User = DataRepository.GetObjectById<User>(Convert.ToInt32(HttpContext.User.Identity.Name));
                torrent.Information = new Information();
                torrent.Information.Torrent = torrent;
                torrent.Information.FileName = Guid.NewGuid().ToString() + ".torrent";
                torrent.Name = form["torrentname"].Trim();

                // calculate info hash
                torrent.Information.InfoHash = BitConverter.ToString(SHA1.Create().ComputeHash(info.Encode())).Replace("-", "");

                if (String.IsNullOrEmpty(torrent.Name))
                {
                    torrent.Name = Path.GetFileNameWithoutExtension(HttpContext.Request.Files[0].FileName);
                }

                if(torrentDictionary.ContainsKey("comment"))
                    torrent.Information.Comment = torrentDictionary["comment"].ToString();

                if (torrentDictionary.ContainsKey("encoding"))
                    torrent.Information.Encoding = torrentDictionary["encoding"].ToString();

                AnnounceUrl aurl = new AnnounceUrl();
                aurl.Information = torrent.Information;
                aurl.Url = torrentDictionary["announce"].ToString();

                torrent.Information.AnnounceUrls.Add(aurl);

                if (torrentDictionary.ContainsKey("announce-list"))
                {
                    BEncodedList announceList = (BEncodedList)torrentDictionary["announce-list"];

                    foreach (BEncodedValue bval in announceList)
                    {
                        AnnounceUrl url = new AnnounceUrl();
                        url.Information = torrent.Information;
                        url.Url = bval.ToString();

                        torrent.Information.AnnounceUrls.Add(url);
                    }
                }

                torrent.Information.PieceLength = Convert.ToInt32(info["piece length"].ToString());
                torrent.Information.Pieces = info["pieces"].ToString();
                torrent.Information.Private = info.ContainsKey("private") && ((BEncodedNumber)info["private"]).Number == 1;

                // read files
                if (info.ContainsKey("files"))
                {
                    // multi files
                    string dir = info["name"].ToString();
                    BEncodedList fileList = (BEncodedList)info["files"];

                    foreach (BEncodedDictionary filedict in fileList)
                    {
                        RushTracker.Core.Models.Torrents.File f = new RushTracker.Core.Models.Torrents.File();
                        f.Information = torrent.Information;
                        f.Length = (int)((BEncodedNumber)filedict["length"]).Number;
                        
                        if (filedict.ContainsKey("md5sum"))
                            f.Md5Summary = filedict["md5sum"].ToString();

                        f.FileName = dir;

                        BEncodedList filenamelist = (BEncodedList)filedict["path"];

                        foreach (BEncodedString filename in filenamelist)
                        {
                            f.FileName += Path.DirectorySeparatorChar;
                            f.FileName += filename.ToString();
                        }

                        torrent.Information.Files.Add(f);
                    }
                }
                else
                {
                    // single file
                    RushTracker.Core.Models.Torrents.File f = new RushTracker.Core.Models.Torrents.File();
                    f.FileName = info["name"].ToString();
                    f.Information = torrent.Information;
                    f.Length = (int)((BEncodedNumber)info["length"]).Number;

                    if (info.ContainsKey("md5sum"))
                        f.Md5Summary = info["md5sum"].ToString();

                    torrent.Information.Files.Add(f);
                }

                // calculate torrent size
                foreach (RushTracker.Core.Models.Torrents.File f in torrent.Information.Files)
                {
                    torrent.Information.Size += f.Length;
                }

                // save torrent file
                HttpContext.Request.Files[0].SaveAs(Path.Combine(Server.MapPath(Site.UploadPath), torrent.Information.FileName));
                DataRepository.SaveObject(torrent);

                TempData["Torrent"] = torrent;
                return RedirectToAction("UploadSucceeded");
            }

            return RedirectToAction("Upload");
        }

        [Authorize]
        public ActionResult UploadSucceeded()
        {
            Torrent t = TempData["Torrent"] as Torrent;

            if (t == null)
            {
                throw new InvalidOperationException("'t' cannot be null.");
            }

            ViewData.Model = t;

            return View();
        }
    }
}
